package com.xuecheng.auth.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;

@Component//重写spring security的DaoAuthenticationProvider的校验密码方法,因为统一了认证入口,有些认证信息不需要校验密码
public class DaoAuthenticationProviderCustom extends DaoAuthenticationProvider {
//原来的DaoAuthenticationProvider 会进行密码校验，现在重新定义DaoAuthenticationProviderCustom类，重写类的additionalAuthenticationChecks方法。
    @Override//屏蔽密码对比
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {

    }

    @Autowired// 这个注释有啥用,不用注入也能用???
    public void setUserDetailsService(UserDetailsService userDetailsService) {
//  你通过 @Autowired 注解让 Spring 注入了 UserDetailsService 实例，但这个实例只是传递到了子类的 setUserDetailsService 方法参数中。只有通过 super.setUserDetailsService(...) 才能将这个实例传递给父类，供父类的逻辑使用。
        super.setUserDetailsService(userDetailsService);
    }

}
// todo
//默认认证流程的兼容性当你没有自定义 DaoAuthenticationProvider 时，Spring Security 会使用默认的 DaoAuthenticationProvider 来处理认证。此时，只要你提供了 UserDetailsService 的实现（如 UserDetailsServiceImpl），Spring 会自动将其装配到默认的 DaoAuthenticationProvider 中，这就是为什么你的 UserDetailsServiceImpl 能生效。
//自定义 Provider 与 UserDetailsService 的关系当你自定义 DaoAuthenticationProviderCustom 后，需要显式将 UserDetailsService 注入到这个自定义 Provider 中（就像你代码中通过 @Autowired setUserDetailsService 做的那样）。如果不做这个绑定，自定义 Provider 就无法获取用户信息，导致认证失败。
//核心逻辑的分工:
//UserDetailsService：负责加载用户信息（用户名、密码、权限等），是认证的数据源。
//DaoAuthenticationProvider：负责执行认证逻辑（包括密码校验，即 additionalAuthenticationChecks 方法的作用）。
//简单说：
//无论是否自定义 DaoAuthenticationProvider，UserDetailsService 都是必须的（用于提供用户数据）。
//自定义 DaoAuthenticationProvider 只是为了修改认证逻辑（比如你这里取消密码校验），但依然需要依赖 UserDetailsService 提供用户信息，因此需要显式绑定。
//你的代码中保留 setUserDetailsService 并调用 super 方法，正是为了维持这种依赖关系，确保自定义 Provider 能正常工作。


//你在 additionalAuthenticationChecks 方法中什么都没写，恰恰就是你重写这个方法的核心目的 ——取消默认的密码校验逻辑。
//原理解释：
//父类的默认行为：父类 DaoAuthenticationProvider 中的 additionalAuthenticationChecks 方法原本是用来校验密码的（通过密码编码器 PasswordEncoder 比对用户输入的密码和 UserDetails 中存储的密码）。
//你的重写效果：当你重写这个方法并让它为空（不做任何操作）时，就跳过了原本的密码校验步骤，这正是你想要的效果 ——"有些认证信息不需要校验密码"。
//为什么要这样做：在统一认证入口的场景下（比如多渠道登录：密码登录、验证码登录、第三方登录等），并非所有认证方式都需要校验密码。通过重写此方法并留白，你实际上是告诉 Spring Security："对于这个自定义认证提供者，不需要进行密码校验"。
//总结：这个空方法看似什么都没做，实则通过 "不执行任何校验逻辑" 的方式，达到了 "取消密码校验" 的目的，这正是你重写该方法的核心价值。
